﻿/*
    Copyright 2014 Mahesh Khanwalkar

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
 */

using System;
using System.IO;
using System.Linq;
using System.Speech.Synthesis;
using System.Windows;
using Microsoft.Win32;
using NAudio.MediaFoundation;
using NAudio.Wave;
using NAudio.Wave.SampleProviders;
using Novacode;

namespace AudioDocs
{
    public partial class WordToAudio
    {
        string _fileName, _outputFileName;
        private SpeechSynthesizer _synthesizer;

        public WordToAudio()
        {
            InitializeComponent();
        }

        private void WordToAudio_OnLoaded(object sender, RoutedEventArgs e)
        {
            _synthesizer = new SpeechSynthesizer();
            var voices = _synthesizer.GetInstalledVoices();

            foreach (var name in voices.Select(voice => voice.VoiceInfo.Name))
            {
                VoiceComboBox.Items.Add(name);
            }

            VoiceComboBox.SelectedIndex = 0;
            MediaFoundationInterop.MFStartup(MediaFoundationInterop.MF_VERSION);
            
        }

        private void BrowseButton_OnClick(object sender, RoutedEventArgs e)
        {
            var openFile = new OpenFileDialog
            {
                Filter = "MS Word 2007-2013|*.docx|MS Word 1998-2003|*.doc",
                FilterIndex = 1
            };

            var result = openFile.ShowDialog();

            /* This is of type bool? so, you can't just do if(result) */
            if (result == true)
            {
                FileNameBox.Text = openFile.SafeFileName;
                _fileName = openFile.FileName;
            }
            else
            {
                MessageBox.Show("You haven't selected a file. Please re-click 'Browse'", "Warning", MessageBoxButton.OK, MessageBoxImage.Information);
            }

        }

        private void SetOutputButton_OnClick(object sender, RoutedEventArgs e)
        {
            var saveFile = new SaveFileDialog
            {
                Filter = "Wave File|*.wav|MP3 File|*.mp3|Windows Media Audio File|*.wma", FilterIndex = 1
            };

            var result = saveFile.ShowDialog();
            if (result == true)
            {
                OutputFileBox.Text = saveFile.SafeFileName;
                _outputFileName = saveFile.FileName;
            }
            else
            {
                MessageBox.Show("You haven't selected an output file. Please re-click 'Set Output'", "Warning", MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }

        private void CreateButton_OnClick(object sender, RoutedEventArgs e)
        {
            try
            {
                if (_fileName == null || _outputFileName == null)
                {
                    MessageBox.Show("Please set both the input and output files", "Error", MessageBoxButton.OK,
                        MessageBoxImage.Error);
                }
                else
                {
                    var doc = DocX.Load(_fileName);
                    var para = doc.Paragraphs;

                    _synthesizer.SelectVoice((string) VoiceComboBox.SelectedItem);
                    ProgressLabel.Visibility = Visibility.Visible;

                    ConversionProgressBar.Visibility = Visibility.Visible;

                    if (_outputFileName.Contains(".wav"))
                    {
                        ConversionProgressBar.Maximum = para.Count - 1;
                    }
                    else
                    {
                        ConversionProgressBar.Maximum = para.Count;
                    }

                    if (_outputFileName.Contains(".wav"))
                    {
                        var synthStream = new FileStream(_outputFileName, FileMode.OpenOrCreate);
                        _synthesizer.SetOutputToWaveStream(synthStream);

                        var count = 1;

                        _synthesizer.SpeakCompleted += (o, args) =>
                        {
                            if (count == para.Count)
                            {
                                ProgressLabel.Dispatcher.Invoke(delegate
                                {
                                    ProgressLabel.Content = "Processing & Conversion Finished";
                                });

                                synthStream.Close();
                            }
                            else
                            {
                                count++;

                                ConversionProgressBar.Dispatcher.Invoke(delegate
                                {
                                    ConversionProgressBar.Value++;
                                });

                            }
                        };

                        foreach (var one in para)
                        {
                            _synthesizer.SpeakAsync(one.Text);
                        }
                    }
                    else if (_outputFileName.Contains(".wma"))
                    {
                        var nOutput = _outputFileName.Replace(".wma", ".wav");
                        var synthStream = new FileStream(nOutput, FileMode.OpenOrCreate);

                        _synthesizer.SetOutputToWaveStream(synthStream);

                        foreach (var one in para)
                        {
                            _synthesizer.SpeakAsync(one.Text);
                        }

                        var count = 1;

                        _synthesizer.SpeakCompleted += async (o, args) =>
                        {
                            if (count == para.Count)
                            {
                                synthStream.Close();

                                var waveReader = new WaveFileReader(nOutput);
                                MediaFoundationEncoder.EncodeToWma(
                                    new SampleToWaveProvider(new SampleChannel(waveReader)), _outputFileName);

                                waveReader.Close();
                                File.Delete(nOutput);

                                await ConversionProgressBar.Dispatcher.InvokeAsync(delegate
                                {
                                    ConversionProgressBar.Value++;
                                });

                                await ProgressLabel.Dispatcher.InvokeAsync(delegate
                                {
                                    ProgressLabel.Content = "Processing & Conversion Finished";
                                });


                            }
                            else
                            {
                                count++;

                                ConversionProgressBar.Dispatcher.Invoke(delegate
                                {
                                    ConversionProgressBar.Value++;
                                });

                            }
                        };

                    }
                    else
                    {
                        var nOutput = _outputFileName.Replace(".mp3", ".wav");
                        var synthStream = new FileStream(nOutput, FileMode.OpenOrCreate);

                        _synthesizer.SetOutputToWaveStream(synthStream);

                        foreach (var one in para)
                        {
                            _synthesizer.SpeakAsync(one.Text);
                        }

                        var count = 1;

                        _synthesizer.SpeakCompleted += async (o, args) =>
                        {
                            if (count == para.Count)
                            {
                                synthStream.Close();

                                var waveReader = new WaveFileReader(nOutput);
                                MediaFoundationEncoder.EncodeToMp3(
                                    new SampleToWaveProvider(new SampleChannel(waveReader)), _outputFileName);

                                waveReader.Close();
                                File.Delete(nOutput);

                                await ConversionProgressBar.Dispatcher.InvokeAsync(delegate
                                {
                                    ConversionProgressBar.Value++;
                                });

                                await ProgressLabel.Dispatcher.InvokeAsync(delegate
                                {
                                    ProgressLabel.Content = "Processing & Conversion Finished";
                                });
                            }
                            else
                            {
                                count++;

                                ConversionProgressBar.Dispatcher.Invoke(delegate
                                {
                                    ConversionProgressBar.Value++;
                                });

                            }
                        };

                    }
                   
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void VolumeSlider_OnValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            var value = (int) VolumeSlider.Value;

            if (VolumeValue != null)
            {
                VolumeValue.Content = value;
            }

            if (_synthesizer != null)
            {
                _synthesizer.Volume = value;
            }
        }

        private void SpeedSlider_OnValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            var value = (int)SpeedSlider.Value;

            if (SpeedValue != null)
            {
                SpeedValue.Content = value;
            }

            if (_synthesizer != null)
            {
                _synthesizer.Rate = value;
            }
        }
    }
}
